use std::{fmt, ops::{Deref, DerefMut}, time::Instant};

use crate::{conn_pool::Conn, Extensions, ManageConnection, Pool};



/// Information about the state of a `Pool`.
#[non_exhaustive]
#[derive(Debug)]
pub struct State {
    /// The number of connections currently being managed by the pool.
    pub connections: u32,
    /// The number of idle connections.
    pub idle_connections: u32,
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<M>
where
    M: ManageConnection,
{
    pub(crate) pool: Pool<M>,
    pub(crate) checkout: Instant,
    pub(crate) conn: Option<Conn<M::Connection>>,
}

impl<M> fmt::Debug for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.conn.as_ref().unwrap().conn, fmt)
    }
}

impl<M> Drop for PooledConnection<M>
where
    M: ManageConnection,
{
    fn drop(&mut self) {
        self.pool.put_back(self.checkout, self.conn.take().unwrap());
    }
}

impl<M> Deref for PooledConnection<M>
where
    M: ManageConnection,
{
    type Target = M::Connection;

    fn deref(&self) -> &M::Connection {
        &self.conn.as_ref().unwrap().conn
    }
}

impl<M> DerefMut for PooledConnection<M>
where
    M: ManageConnection,
{
    fn deref_mut(&mut self) -> &mut M::Connection {
        &mut self.conn.as_mut().unwrap().conn
    }
}

impl<M> PooledConnection<M>
where
    M: ManageConnection,
{
    /// Returns a shared reference to the extensions associated with this connection.
    pub fn extensions(this: &Self) -> &Extensions {
        &this.conn.as_ref().unwrap().extensions
    }

    /// Returns a mutable reference to the extensions associated with this connection.
    pub fn extensions_mut(this: &mut Self) -> &mut Extensions {
        &mut this.conn.as_mut().unwrap().extensions
    }
}
